
const utils = {
    //通过ID获取元素
     id$(id){
        return document.getElementById(id)
    },


    //通过css选择器获取元素
     ele$(ele){
        return document.querySelector(ele)
    },


    //通过css选择器获取元素[伪数组]
     eles$(ele){
        return document.querySelectorAll(ele)
    },


    //设置或者获取非行间样式
     css$(ele,attr,value){
        if(!value){
        return window.getComputedStyle ? 
                window.getComputedStyle(ele)[attr] : 
                ele.currentStyle[attr]
        }

        ele.style [attr] = value
    },


    //随机数
     Math$(a,b){
        return Math.floor(Math.random()*(b-a +1) +a)
    },


    //rgb颜色
     rgb$(){
        return "rgb("+Math$(0,255)+","+Math$(0,255)+","+Math$(0,255)+")"
    },


    //获取光标到页面的距离(兼容IE9以下)
     page(e){
        if(e.pageX){
            return {X:e.pageX ,Y: e.pageY}
        }else{
            var _left = document.documentElement ?
                        document.documentElement.scrollLeft :
                        document.body.scrollLeft
            var _top = document.documentElement ? 
                    document.documentElement.scrollTop :
                    document.body.scrollTop
        }
        return {X:_left + e.clientX , Y:_top + e.clientY}
    
    },


    //获取元素的宽度 + padding
     clientWidth$(ele){
        if(css$(ele,"display") === "none"){
            return parseFloat(css(ele,"width")) + parseFloat(css$(ele,"paddingLeft")) + parseFloat(css$(ele,"paddingRight"))
        }
        return ele.clientWidth
    },

    //获取元素的高度 + padding
     clientHeight$(ele){
        if(css$(ele,"display") === "none"){
            return parseFloat(css(ele,"height")) + parseFloat(css$(ele,"paddingLeft")) + parseFloat(css$(ele,"paddingRight"))
        }
        return ele.clientHeight
    },


    //获取元素的宽度 + padding + border
     offsetWidth$(ele){
        if(css$(ele,"display" === "none")){
            return clientWidth$(ele) + parseFloat(css$(ele,"borderLeftWidth")) + parseFloat(css$(ele,"borderRightWidth"))
        }
        return ele.offsetWidth
    },

    //获取元素的高度 + padding + border
     offsetHeight$(ele){
        if(css$(ele,"display" === "none")){
            return clientHeight$(ele) + parseFloat(css$(ele,"borderTopWidth")) + parseFloat(css$(ele,"borderBottomWidth"))
        }
        return ele.offsetHeight
    },


    //添加时间监听
     on$(ele,type,fn){
        if(type.indexOf("on") == 0){
            type = type.slice(2)
        }
        ele.addEventListener ? ele.addEventListener(type,fn) : ele.attachEvent("on" + type,fn)     
    },


    //移除事件监听
     off$(ele,type,fn){
        if(type.indexOf("on") == 0){
            type = type.slice(2)
        }
        ele.removeEventListener ? ele.removeEventListener(type,fn) : ele.detachEvent("on" + type,fn)     
    },



    //单属性匀速运动
    /* 
    @param  ele 要改变的元素
    @param  attr 要改变的属性
    @param  target 运动的终点
    @param  speed 完成时间

    */
     animate$(ele,attr,target,speed){
        clearInterval(ele.timer)    //每次点击时，先清除该元素身上在执行的定时器，解决每次点击会开启多个定时器的问题
        let strat = parseFloat(css$(ele,attr))    //初始值 起点
        let step = (target-strat) / speed
        let time1 = new Date().getTime()
        ele.timer = setInterval(function (){
            let time2 = new Date().getTime()
            let cha = Math.min((time2 - time1),speed)    //这个时间差等于speed的几率很小，如果不和speed相等，该元素改变的属性值会有误差
            let res = css$(id$("box","left"))
            res = strat + (step*cha)
            ele.style[attr] = res +"px"
            if(cha >= speed){
                clearInterval(ele.timer)
            }
        },10)
    },



    //多属性匀速运动
    /* 
    @param    ele    要改变的元素
    @param    obj    要改变的属性 是一个对象
    @param    speed  完成时间
    @param    fn     代码执行完毕后执行的函数
    */
     animates$(ele,obj,speed,fn){
        clearInterval(ele.timer)
        let strat= {}, range = {}, time1 = new Date().getTime()
        for(var key in obj){
            strat[key] = parseFloat(css$(ele,key))     //分别获取属性的初始值
            range[key] = parseFloat(obj[key]) - strat[key]    //分别计算出属性的运动区间
        }
        ele.timer = setInterval(function (){
            let time2 = new Date().getTime()
            let cha = Math.min((time2 - time1),speed)
            for(var key in obj){ 
                let result = parseFloat(range[key]) / speed * cha + parseFloat(strat[key])
                ele.style[key] = result +"px"
            }
            if(cha >= speed){
                clearInterval(ele.timer)
                fn && fn()
            }
        },10) 
    },



    //多属性匀速缓冲运动
    /* 
    @param    ele    要改变的元素
    @param    obj    要改变的属性 是一个对象
    @param    speed  完成时间
    @param    fn     代码执行完毕后执行的函数
    */
     move$(ele,obj,fn){
        let start = {},    //获取相对应的起点值
            distance = {},    //动态获取剩下距离
            speed = {},     //动态改变单位速度
            count = 0     //有多少属性
        for(var key in obj) {
            start[key] = parseInt(css$(ele,key))
            count++
        }
        ele.timer = setInterval(() =>{
            let n = 0      //运动完成的属性
            for(var key in obj){
                distance[key] = parseInt(obj[key]) - parseInt(start[key])   //如果终点减去起点为负数，那么单位时间向上取整就会有值为0的情况
                speed[key] = distance[key] > 0 ? Math.ceil(distance[key] / 30) : Math.floor(distance[key] / 30)
                start[key] += speed[key]   //定时器每执行一次，起点都要改变
                ele.style[key] = start[key] +"px"
                if(obj[key] === start[key]){
                    n++
                } 
                if(n === count){
                    clearInterval(ele.timer)
                    fn && fn()
                }
            }
        },10)
    },


    /* 
    @param {string}   key    要取的cookie名称
    @return {string}         返回获取的cookie值
    */
     getCookie(key){ 
        let str = document.cookie
        let arr = str.split("; ")
        let obj = {}
        arr.forEach(item=>{
            let subArr = item.split("=")
            obj[subArr[0]] = decodeURIComponent(subArr[1])
        })
        return obj[key]
    },


    /* 
    @param {string}   key       要存的cookie名称
    @param {string}   value     要存的cookie值
    @param {Object}   [options] {path:'/',expires:7}
    */
   setCookie(key,value,options){    //可以存多条coolie
        let str = `${key} = ${encodeURIComponent(value)}`
        if(options){
            if(options.path){
                str +=`;path = ${options.path}`
            }
            if(options.expires){
                let date = new Date()
                date.setDate(date.getDate() + options.expires )
                str +=`;expires = ${date.toUTCString()}`
            }
        }
        document.cookie = str
    },



    /* 
    @param {string}   url    请求的地址
    @param {Object}   query  请求要传递的参数
    @param {string}   fn     回调函数 (发送请求是异步代码，取值会有问题)       在调用get方法时，传入一个函数并且有一个形参，接收resp
    @param {boolean}  [isJson] 默认为true(转为满足JSON格式的字符串)
    */
   get (url, query, fn, isJson=true) {
       if(query){
          url +='?'       //请求方式为get就要在url拼接
          for(var key in query){
              url +=`${key}=${query[key]}&`
          }
          url = url.slice(0,-1)
       }
       let xml = new XMLHttpRequest()
       xml.open('get',url)
       xml.send()
       xml.onreadystatechange = ()=>{
           if(xml.readyState === 4){
               if(xml.status === 200){
                   const resp = isJson ? JSON.parse(xml.responseText) : xml.responseText                   
                   fn && fn(resp)   //调用函数fn时，传了一个实参   
               }
           }
       }
   },



    /* 
    @param {string}   url    请求的地址
    @param {Object}   query  请求要传递的参数
    @param {string}   fn     回调函数 (发送请求是异步代码，取值会有问题)       在调用get方法时，传入一个匿名函数并且有一个形参，接收resp
    @param {boolean}  [isJson] 默认为true(转为满足JSON格式的字符串)
    */
    post(url, query, fn, isJson=true) {
        if (query) {
            var str = ''       //请求方式为post,拼接数据然后设置为请求头
            for (var key in query) {
                str += `${key}=${query[key]}&`
            }
            str = str.slice(0, -1)
        }
        var xml = new XMLHttpRequest()
        xml.open('post', url)
        xml.setRequestHeader("Content-type","application/x-www-form-urlencoded")   //设置为请求头部
        xml.send(str)
        xml.onreadystatechange = () => {
            if (xml.readyState === 4) {
                if (xml.status === 200) {
                    const resp = isJson ? JSON.parse(xml.responseText) : xml.responseText
                    fn && fn(resp)   //调用函数fn时，传了一个实参  
                }
            }
        }
    },



    /* 
    @param {string}   url    请求的地址
    @param {string}   cbName 回调函数名(必须是全局函数)
    @param {Object}   query  请求要传递的参数
    */
    jsonp (url,cbName,query) {   //跨域访问，发送请求
        url +=`?cb=${cbName}`
        if(query){
            for(var key in query){
                url += `&${key}=${query[key]}`
            }
        }
        var script = document.createElement("script")
        script.src = url
        document.body.appendChild(script)
        document.body.removeChild(script)  //每次请求都会创建一个script标签，所有拿到数据后就要删掉
    },



    /* 基于pomise Ajax的get请求
    @param {string}   url    请求的地址
    @param {Object}   query  请求要传递的参数
    @param {boolean}  [isJson] 默认为true(转为满足JSON格式的字符串)
    */
    fetchG (url,query,isJson = true) {
        if(query){
            url += '?'
            for(var key in query){
                url +=`${key}=${query[key]}&`
            }
            url = url.slice(0,-1)
        }
        return new Promise((resolve,reject)=>{
            var xml = new XMLHttpRequest()
            xml.open('get',url)
            xml.send()
            xml.onreadystatechange = function () {
                if(xml.readyState === 4){
                    if(xml.status === 200){
                        resolve(isJson ? JSON.parse(xml.responseText) : xml.responseText)
                    }else{
                        reject()
                    }
                }
            }
        })
    },




    /* 基于pomise Ajax的post请求
    @param {string}   url    请求的地址
    @param {Object}   query  请求要传递的参数
    @param {boolean}  [isJson] 默认为true(转为满足JSON格式的字符串)
    */
   fetchP (url,query,isJson = true) {
    if(query){
        var str = ''
        for(var key in query){
            str +=`${key}=${query[key]}&`
        }
        str = str.slice(0,-1)
        }
        return new Promise((resolve,reject)=>{
            var xml = new XMLHttpRequest()
            xml.open('post',url)
            xml.setRequestHeader("Content-type","application/x-www-form-urlencoded")
            xml.send(str)
            xml.onreadystatechange = function () {
                if(xml.readyState === 4){
                    if(xml.status === 200){
                        resolve(isJson ? JSON.parse(xml.responseText) : xml.responseText)
                    }else{
                        reject()
                    }
                }
            }
        })
    },



}